home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / et / et3_0-a1.lha / et3 / src / TreeView.C < prev    next >
C/C++ Source or Header  |  1992-08-26  |  17KB  |  783 lines

  1. #ifdef __GNUG__
  2. #pragma implementation
  3. #endif
  4.  
  5. #include "TreeView.h"
  6.  
  7. #include "Class.h"
  8. #include "Menu.h"
  9. #include "String.h"
  10. #include "OrdColl.h"
  11. #include "TextItem.h"
  12. #include "Math.h"
  13.  
  14. static bool treetest;
  15.  
  16. void Indent(OStream &s, int l)
  17. {
  18.     for (int i= 0; i<l; i++)
  19.     s << " ";
  20. }
  21.  
  22. //---- New ---------------------------------------------------------------------
  23.  
  24. int offset(Point p, Point a, Point b)
  25. {
  26.     int d, s;
  27.     
  28.     if (b.x <= p.x || p.x+a.x <= 0)
  29.     return 0;
  30.         
  31.     int t= b.x*a.y-a.x*b.y;
  32.     
  33.     if (t > 0) {
  34.     if (p.x < 0) {
  35.         s= p.x * a.y;
  36.         d= s/a.x-p.y;
  37.     } else if (p.x > 0) {
  38.         s= p.x * b.y;
  39.         d= s/b.x-p.y;
  40.     } else
  41.         d= -p.y;
  42.     } else {
  43.     if (b.x < p.x+a.x) {
  44.         s= (b.x-p.x) * a.y;
  45.         d= b.y-(p.y+s/a.x);
  46.     } else if (b.x > p.x+a.x) {
  47.         s= (a.x+p.x) * b.y;
  48.         d= s/b.x-(p.y+a.y);
  49.     } else
  50.         d= b.y-(p.y+a.y);
  51.     }
  52.     return Math::Max(0, d);
  53. }
  54.  
  55. line *bridge(line *line1, Point p1, line *line2, Point p2)
  56. {
  57.     Point d;
  58.     
  59.     d.x= p2.x+line2->d.x-p1.x;
  60.     if (line2->d.x == 0)
  61.     d.y= line2->d.y;
  62.     else
  63.     d.y= (d.x*line2->d.y)/line2->d.x;
  64.     line *r= new line(d, line2->link);
  65.     line1->link= new line(Point(0, p2.y + line2->d.y - d.y - p1.y), r);
  66.     return r;
  67. }
  68.  
  69. void line::draw(Point pos)
  70. {
  71.     GrPaintLine(gHighlightColor, 1, eDefaultCap, pos, pos+d);
  72.     if (link)
  73.     link->draw(pos+d);
  74. }
  75.  
  76. void polygon::draw(int h, Point pos)
  77. {
  78.     if (upper.head)
  79.     upper.head->draw(Point(pos.x, pos.y));
  80.     if (lower.head)
  81.     lower.head->draw(Point(pos.x, pos.y+h));
  82. }
  83.  
  84. Point polygon::bbox(int h)
  85. {
  86.     Point pos;
  87.     int minx, maxx, miny, maxy;
  88.     line *p;
  89.     minx= maxx= miny= maxy= 0;
  90.     for (p= upper.head; p; p= p->link) {
  91.     pos+= p->d;
  92.     minx= Math::Min(pos.x, minx);
  93.     maxx= Math::Max(pos.x, maxx);
  94.     miny= Math::Min(pos.y, miny);
  95.     maxy= Math::Max(pos.y, maxy);
  96.     }
  97.     pos= Point(0, h);
  98.     for (p= lower.head; p; p= p->link) {
  99.     pos+= p->d;
  100.     minx= Math::Min(pos.x, minx);
  101.     maxx= Math::Max(pos.x, maxx);
  102.     miny= Math::Min(pos.y, miny);
  103.     maxy= Math::Max(pos.y, maxy);
  104.     }
  105.     return Point(maxx-minx, maxy-miny);
  106. }
  107.  
  108. int polygon::loffset()
  109. {
  110.     int posy= 0, miny= 0;
  111.     line *p;
  112.     for (p= upper.head; p; p= p->link) {
  113.     posy+= p->d.y;
  114.     miny= Math::Min(posy, miny);
  115.     }
  116.     return miny;
  117. }
  118.  
  119. int polygon::merge(polygon *c2)
  120. {
  121.     Point p;
  122.     int total= 0, d;
  123.     line *low, *up, *b;
  124.     
  125.     up= lower.head;
  126.     low= c2->upper.head;
  127.     
  128.     while (low && up) {
  129.     d= offset(p, low->d, up->d);
  130.     p.y+= d;
  131.     total+= d;
  132.         
  133.     if (p.x + low->d.x <= up->d.x) {
  134.         p+= low->d;
  135.         low= low->link;
  136.     } else {
  137.         p-= up->d;
  138.         up= up->link;
  139.     }
  140.     }
  141.     
  142.     if (low) {
  143.     b= bridge(upper.tail, Point(0,0), low, p);
  144.     upper.tail= (b->link) ? c2->upper.tail : b;
  145.     lower.tail= c2->lower.tail;
  146.     } else {
  147.     b= bridge(c2->lower.tail, p, up, Point(0,0));
  148.     if (b->link == 0)
  149.         lower.tail= b;
  150.     }
  151.     lower.head= c2->lower.head;
  152.     
  153.     return total;
  154. }
  155.  
  156. int TreeNode::join()
  157. {
  158.     Iter next(MakeIterator());
  159.     TreeNode *c= (TreeNode*) next(); // skip label
  160.     int d, h, sum;
  161.     
  162.     c= (TreeNode*) next();
  163.     c->GetMinSize();
  164.     contour= c->contour;
  165.     sum= h= c->height() + Gap().y;
  166.     while (c= (TreeNode*) next()) {
  167.     c->GetMinSize();
  168.     d= contour.merge(&c->contour);
  169.     c->offset= Point(0, d+h);
  170.     h= c->height() + Gap().y;
  171.     sum+= d+h;
  172.     }
  173.     return sum-Gap().y;
  174. }
  175.  
  176. //---- TreeNode ----------------------------------------------------------------
  177.  
  178. NewMetaImpl0(TreeNode, CompositeVObject);
  179.  
  180. TreeNode::TreeNode(int id, SeqCollection *cp) : CompositeVObject(id, cp)
  181. {
  182. }
  183.  
  184. TreeNode::TreeNode(int va_(id), ...) : CompositeVObject(va_(id), (SeqCollection*)0)
  185. {
  186.     va_list ap;
  187.     va_start(ap,va_(id));
  188.     SetItems(ap);
  189.     va_end(ap);
  190. }
  191.  
  192. TreeNode::TreeNode(int id, va_list ap) : CompositeVObject(id, ap)
  193. {
  194. }
  195.  
  196. extern "C" abort();
  197.  
  198. TreeView *TreeNode::GetTreeView()
  199. {
  200.     TreeView *tv= (TreeView*) GetView();
  201.     if (tv == 0) {
  202.     fprintf(stderr, "GetTreeView() == 0\n");
  203.     abort();
  204.     }
  205.     return tv;
  206. }
  207.  
  208. void TreeNode::SetOrigin(Point at)
  209. {
  210.     Iter next(MakeIterator());
  211.     TreeNode *dip, *first;
  212.  
  213.     if (treetest) fprintf(stderr, "TreeNode::SetOrigin\n");
  214.     VObject::SetOrigin(at);
  215.     first= (TreeNode*) next();
  216.  
  217.     if (Layout() == eTLNew) { // eTLNew
  218.     at.y-= contour.loffset();
  219.     first->SetOrigin(at);
  220.     
  221.     while (dip= (TreeNode*) next()) {
  222.         at+= dip->offset;
  223.         dip->SetOrigin(Point(at.x, at.y + dip->contour.loffset()));
  224.     }
  225.     return;
  226.     }
  227.     
  228.     if (Collapsed() || Size() == 1)
  229.     first->SetOrigin(at);
  230.     else {
  231.     switch (Layout()) {
  232.     case eTLTopDown:
  233.         first->SetOrigin(at+Point((Width()-first->Width())/2, 0));
  234.         at.y+= Gap().y+first->Height();
  235.         while (dip= (TreeNode*) next()) {
  236.         dip->SetOrigin(at);
  237.         at.x+= dip->Width()+Gap().x;
  238.         }
  239.         break;
  240.     case eTLIndented:
  241.     case eTLLeftRight:
  242.         if (Layout() == eTLIndented) {
  243.         first->SetOrigin(at);
  244.         at+= Point(Gap().x, first->Height()+Gap().y);
  245.         } else {
  246.         first->SetOrigin(at+Point(0, (Height()-first->Height())/2));
  247.         at.x+= Gap().x+first->Width();
  248.         }
  249.         while (dip= (TreeNode*) next()) {
  250.         dip->SetOrigin(at);
  251.         at.y+= dip->Height()+Gap().y;
  252.         }
  253.         break;
  254.     case eTLNew:
  255.         break;
  256.     }
  257.     }
  258. }
  259.  
  260. void TreeNode::SetExtent(Point e)
  261. {
  262.     if (treetest) fprintf(stderr, "TreeNode::SetExtent\n");
  263.     if (Collapsed()) {
  264.     VObject::SetExtent(e);
  265.     } else {
  266.     CompositeVObject::SetExtent(e);
  267.     }
  268. }
  269.  
  270. void TreeNode::Open(bool mode)
  271. {
  272.     if (IsOpen() == mode)
  273.     return;
  274.     CompositeVObject::Open(mode);
  275.     if (GetTreeView())
  276.     GetTreeView()->OpenTreeNode(this, mode);    
  277. }
  278.  
  279. void TreeNode::Collapse()
  280. {
  281.     Iter next(MakeIterator());
  282.     VObject *vop;
  283.     next();
  284.     while (vop= (VObject*)next())
  285.     vop->Open(Collapsed());
  286.     InvertFlag(eTreeNodeCollapsed);
  287.     ExtentChanged(this);
  288. }
  289.  
  290. Metric TreeNode::GetMinSize()
  291. {
  292.     if (treetest) fprintf(stderr, "TreeNode::GetMinSize\n");
  293.     if (Layout() == eTLNew) { //case eTLNew:
  294.     At(0)->CalcExtent();
  295.     if (Size() > 1) { // a node
  296.         int h= join();
  297.         int x= Gap().x;
  298.         int p2y= (h-height())/2;
  299.         int p1y= p2y+height()-h;
  300.         ((TreeNode*)At(1))->offset= Point(x+width(), p1y);
  301.         contour.upper.head= new line(Point(width(), 0),
  302.                     new line(Point(x, p1y), contour.upper.head));
  303.         contour.lower.head= new line(Point(width(), 0),
  304.                     new line(Point(x, p2y), contour.lower.head));
  305.     } else {        // a leaf
  306.         contour.upper.tail= new line(Point(width(),0), 0);
  307.         contour.upper.head= contour.upper.tail;
  308.         contour.lower.tail= new line(Point(0, -height()), 0);
  309.         contour.lower.head= new line(Point(width(),0), contour.lower.tail);
  310.     }
  311.     return contentRect.extent= contour.bbox(height());
  312.     }
  313.     
  314.     Metric m, m1, mn;
  315.     Iter next(MakeIterator());
  316.     VObject *dip, *first;
  317.  
  318.     first= (VObject*) next();
  319.  
  320.     if (Collapsed() || Size() == 1)
  321.     return first->GetMinSize();
  322.     m1= first->GetMinSize();
  323.     switch(Layout()) {
  324.     case eTLTopDown:
  325.     while (dip= (VObject*) next()) {
  326.         mn= dip->GetMinSize();
  327.         m.extent.y= Math::Max(m.extent.y, mn.extent.y);
  328.         m.extent.x+= mn.extent.x+Gap().x;
  329.     }
  330.     m.extent.x-= Gap().x;
  331.     m.extent.x= Math::Max(m.extent.x, m1.extent.x);
  332.     m.extent.y+= m1.extent.y+Gap().y;
  333.     m.base= m.extent.y;
  334.     break;
  335.     case eTLIndented:
  336.     case eTLLeftRight:
  337.     while (dip= (VObject*) next()) {
  338.         mn= dip->GetMinSize();
  339.         m.extent.x= Math::Max(m.extent.x, mn.extent.x);
  340.         m.extent.y+= mn.extent.y+Gap().y;
  341.     }
  342.     if (Layout() == eTLIndented) {
  343.         m.extent.y+= m1.extent.y;
  344.         m.extent.x+= Gap().x;
  345.         m.extent.x= Math::Max(m.extent.x, m1.extent.x);
  346.         m.base= m1.base;
  347.     } else {
  348.         m.extent.y-= Gap().y;
  349.         m.extent.y= Math::Max(m.extent.y, m1.extent.y);
  350.         m.extent.x+= m1.extent.x+Gap().x;
  351.         m.base= m.extent.y;
  352.     }
  353.     break;
  354.  
  355.     case eTLNew:
  356.     break;
  357.     }
  358.     return m;
  359. }
  360.  
  361. void TreeNode::Draw(Rectangle r)
  362. {
  363.     VObject *sel= GetTreeView()->GetSelection(), *vop;
  364.  
  365.     if (Collapsed()) {
  366.     vop= At(0);
  367.     vop->DrawAll(r, vop == sel);
  368.     GrStrokeRoundRect(contentRect, gPoint10);
  369.     } else {
  370.     if (ConnType() != eTCNone) {
  371.         GrSetPenNormal();
  372.         DrawConnections();
  373.     }
  374.     Iter next(MakeIterator());
  375.     while (vop= (VObject*)next())
  376.         vop->DrawAll(r, vop == sel);
  377.     }
  378. }
  379.  
  380. void TreeNode::DrawConnections()
  381. {
  382.     if (Size() == 1)
  383.     return;
  384.     Iter next(MakeIterator());
  385.     VObject *dip, *first;
  386.     Point p1, p2;
  387.     int l;
  388.  
  389.     GrSetPenSize(0);
  390.     first= (VObject*) next();
  391.     
  392.     if (Layout() == eTLLeftRight) {
  393.     Point start= first->contentRect.E();
  394.     while (dip= (VObject*) next())
  395.         GrLine(start, dip->At(0)->contentRect.W());
  396.     return;
  397.     }
  398.  
  399.     switch (Layout()) {
  400.     case eTLNew:
  401.     break;
  402.     case eTLIndented:
  403.     if (ConnType() == eTCPerpendicular) {
  404.         l= Gap().x/2;
  405.         p1= first->contentRect.SW() + Point(l, 0);
  406.         while (dip= (VObject*) next()) {
  407.         p2= dip->contentRect.origin+Point(0, dip->Base()-5);
  408.         GrLine(p2, p2-Point(l,0));
  409.         }
  410.         GrLine(p1, p2-Point(l,0));
  411.     }
  412.     break;
  413.     case eTLTopDown:
  414.     if (ConnType() == eTCPerpendicular || ConnType() == eTCDiagonal2) {
  415.         l= ConnType() == eTCPerpendicular ? Gap().y/2 : 5;
  416.         p1= first->contentRect.S();
  417.         p2= p1+Point(0,l);
  418.         GrLine(p1, p2);
  419.         while (dip= (VObject*) next())
  420.         GrLine(dip->contentRect.N(), dip->contentRect.N()-Point(0,l));
  421.     }
  422.     if (ConnType() == eTCDiagonal || ConnType() == eTCDiagonal2) {
  423.         Iter next(MakeIterator());
  424.         first= (VObject*) next();
  425.         l= ConnType() == eTCDiagonal ? 0 : 5;
  426.         p1= first->contentRect.S()+Point(0,l);
  427.  
  428.         while (dip= (VObject*) next())
  429.         GrLine(p1, dip->contentRect.N()-Point(0,l));
  430.     } else {
  431.         l= Gap().y/2;
  432.         p1= At(1)->contentRect.N()-Point(0,l);
  433.         p2= At(Size()-1)->contentRect.N()-Point(0,l);
  434.         GrLine(p1, p2);
  435.     }
  436.     break;
  437.     case eTLLeftRight:
  438.     if (ConnType() == eTCPerpendicular || ConnType() == eTCDiagonal2) {
  439.         l= ConnType() == eTCPerpendicular ? Gap().x/2 : 5;
  440.         p1= first->contentRect.E();
  441.         p2= p1+Point(l,0);
  442.         GrLine(p1, p2);
  443.         while (dip= (VObject*) next())
  444.         GrLine(dip->contentRect.W(), dip->contentRect.W()-Point(l,0));
  445.     }
  446.     if (ConnType() == eTCDiagonal || ConnType() == eTCDiagonal2) {
  447.         Iter next(MakeIterator());
  448.         first= (VObject*) next();
  449.         l= ConnType() == eTCDiagonal ? 0 : 5;
  450.         p1= first->contentRect.E()+Point(l,0);
  451.  
  452.         while (dip= (VObject*) next())
  453.         GrLine(p1, dip->contentRect.W()-Point(l,0));
  454.     } else {
  455.         l= Gap().x/2;
  456.         p1= At(1)->contentRect.W()-Point(l,0);
  457.         p2= At(Size()-1)->contentRect.W()-Point(l,0);
  458.         GrLine(p1, p2);
  459.     }
  460.     break;
  461.     }
  462. }
  463.  
  464. void TreeNode::Outline2(Point p1, Point p2)
  465. {
  466.     Rectangle r= NormRect(p1, p2);
  467.     if (Collapsed())
  468.     GrStrokeRoundRect(r, gPoint10);
  469.     else if (Layout() == eTLIndented) {
  470.     Point sw= At(0)->contentRect.SW()+(r.origin-contentRect.origin);
  471.     int gap= Gap().x;
  472.  
  473.     GrLine(r.NW(), r.NE());
  474.     GrLine(r.NE()+Point(0,1), r.SE());
  475. #ifdef sun
  476.     GrLine(r.SE()-Point(1,0), r.SW()+Point(gap,0));
  477. #else
  478.     Point pp= r.SW()+Point(gap,0);
  479.     GrLine(r.SE()-Point(1,0), pp);
  480. #endif
  481.     GrLine(r.SW()+Point(gap,-1), r.NW()+Point(gap, At(0)->Height()));
  482.     GrLine(sw+Point(gap-1,0), sw);
  483.     GrLine(sw-Point(0,1), r.NW());
  484.     } else
  485.     CompositeVObject::Outline2(p1, p2);
  486. }
  487.  
  488. void TreeNode::Highlight(HighlightState hst)
  489. {
  490.     At(0)->Highlight(hst);
  491. }
  492.  
  493. Command *TreeNode::DispatchEvents(Point lp, Token &t, Clipper *vf)
  494. {
  495.     if (At(0)->ContainsPoint(lp))
  496.     return VObject::DispatchEvents(lp, t, vf);
  497.     if (Collapsed())
  498.     return 0;
  499.     return CompositeVObject::DispatchEvents(lp, t, vf);
  500. }
  501.  
  502. Command *TreeNode::DoMiddleButtonDownCommand(Point, Token t, int)
  503. {
  504.     if (t.Flags & eFlgShiftKey) 
  505.     GetTreeView()->Promote(this);
  506.     else
  507.     GetTreeView()->Collapse(this);
  508.     return gNoChanges;
  509. }
  510.  
  511. Command *TreeNode::DoLeftButtonDownCommand(Point, Token, int cl)
  512. {
  513.     return GetTreeView()->GetNodeSelector(this, cl);
  514. }
  515.     
  516. GrCursor TreeNode::GetCursor(Point lp)
  517. {
  518.     if (Collapsed() && At(0)->ContainsPoint(lp))
  519.     return eCrsBoldCross;
  520.     return CompositeVObject::GetCursor(lp);
  521. }
  522.  
  523. void TreeNode::Export(OStream &s, int level)
  524. {    
  525.     Iter next(MakeIterator());
  526.     TreeNode *tn;
  527.  
  528.     tn= (TreeNode*) next();
  529.     if (tn) {
  530.     Indent(s, level);
  531.     s << tn->AsString() NL;
  532.     while (tn= (TreeNode*) next()) {
  533.         if (tn->IsKindOf(TreeNode))
  534.         tn->Export(s, level+2);
  535.         else {
  536.         Indent(s, level+2);
  537.         s << tn->AsString() NL;
  538.         }
  539.     }
  540.     }
  541. }
  542.  
  543. VObject *TreeNode::Detect(BoolFun f, void *arg)
  544. {
  545.     if (!Collapsed()) {
  546.     VObject *vop= CompositeVObject::Detect(f, arg);
  547.     if (vop && !vop->IsKindOf(TreeNode))
  548.         return vop;
  549.     }
  550.     return 0;
  551. }
  552.  
  553. VObject *TreeNode::FindExpandedItem(VObject *vop)
  554. {
  555.     VObject *op, *found= 0;
  556.     
  557.     Iter next(MakeIterator());    
  558.     while ((op= (VObject*)next()) && !found) {
  559.     if (op->IsKindOf(TreeNode)) 
  560.         found= ((TreeNode*)op)->FindExpandedItem(vop);
  561.     else
  562.         found= op->FindItem(vop);
  563.     if (Collapsed() && found)
  564.         found= At(0);
  565.     }
  566.     return found;
  567. }
  568.  
  569. //---- TreeNodeSelector ----------------------------------------------------------------
  570.  
  571. TreeNodeSelector::TreeNodeSelector(TreeNode *s, int cl)
  572. {
  573.     item= s;
  574.     lastinside= FALSE;
  575.     clicks= cl;
  576. }
  577.  
  578. void TreeNodeSelector::TrackFeedback(Point, Point, bool)
  579. {
  580.     VObject *image= item->At(0);
  581.     if (item && (lastinside != inside)) {
  582.     item->At(0)->Outline(0);
  583.     lastinside= inside;
  584.     }
  585. }
  586.  
  587. Command *TreeNodeSelector::TrackMouse(TrackPhase atp, Point, Point, Point np)
  588. {
  589.     VObject *image= item->At(0);
  590.     inside= image->ContainsPoint(np);
  591.     if (atp == eTrackRelease) {
  592.     if (item && lastinside) {
  593.         image->Outline(0);
  594.         item->GetTreeView()->SetSelection(image);
  595.         return item->GetTreeView()->NodeSelected(item->At(0), clicks);
  596.     }                
  597.     }
  598.     return this;
  599. }
  600.  
  601. //---- TreeView ----------------------------------------------------------------
  602.  
  603. NewMetaImpl(TreeView, DialogView, (TE(layout), TE(connType), TP(tree), TP(selection)));
  604.  
  605. TreeView::TreeView(EvtHandler *eh, TreeLayout lt, TreeConnection tc) 
  606.                                 : DialogView(eh)
  607. {
  608.     connType= tc;
  609.     layout= lt;
  610.     gap= Point(30, 4);
  611.     tree= oldtree= 0;
  612.     selection= 0;
  613. }
  614.  
  615. VObject *TreeView::DoCreateDialog()
  616. {
  617.     return new TextItem("root");
  618. }
  619.  
  620. void TreeView::SetLayout(TreeLayout tl)
  621. {
  622.     layout= tl;
  623.     switch (layout) {
  624.     case eTLIndented:
  625.     gap= Point(20, 2);
  626.     break;
  627.     case eTLTopDown:
  628.     gap= Point(10, 40);
  629.     break;
  630.     case eTLLeftRight:
  631.     gap= Point(30, 4);
  632.     break;
  633.     case eTLNew:
  634.     break;
  635.     }
  636.     CalcLayout();
  637. }
  638.  
  639. void TreeView::SetConnType(TreeConnection ct)
  640. {
  641.     connType= ct;
  642.     CalcLayout();
  643. }
  644.  
  645. void TreeView::SetTree(TreeNode *t, bool freeold)
  646. {
  647.     if (freeold && tree) {
  648.     tree->FreeAll();
  649.     delete tree;
  650.     }
  651.     SetDialog(tree= t);
  652.     oldtree= 0;
  653. }
  654.  
  655. void TreeView::SetExtent(Point e)
  656. {
  657.     if (GetExtent() != e)    // update fix
  658.     ForceRedraw();
  659.     DialogView::SetExtent(e);
  660. }
  661.  
  662. void TreeView::Promote(TreeNode *newt)
  663. {
  664.     if (oldtree != 0 && newt == tree) {
  665.     SetTree(oldtree, FALSE);
  666.     oldtree= 0;
  667.     } else {
  668.     if (oldtree == 0)
  669.         oldtree= tree;
  670.     SetTree(newt, FALSE);
  671.     }
  672.     ForceRedraw();
  673. }
  674.  
  675. void TreeView::Collapse(TreeNode *tn)
  676. {
  677.     tn->Collapse();
  678. }
  679.  
  680. void TreeView::OpenTreeNode(TreeNode*, bool)
  681. {
  682. }
  683.  
  684. OStream &TreeView::PrintOn(OStream &s)
  685. {
  686.     return s << layout SP << connType SP << gap SP << tree SP;
  687. }
  688.  
  689. IStream &TreeView::ReadFrom(IStream &s)
  690. {
  691.     s >> Enum(layout) >> Enum(connType) >> gap >> tree;
  692.     SetTree(tree);
  693.     return s;
  694. }
  695.  
  696. void TreeView::Export(OStream &s)
  697. {
  698.     if (tree)
  699.     tree->Export(s, 0);
  700. }
  701.  
  702. VObject *TreeView::FindNode(VObject *gp)
  703. {
  704.     if (tree)
  705.     return tree->FindExpandedItem(gp);
  706.     return 0;
  707. }
  708.  
  709. Command *TreeView::GetNodeSelector(TreeNode *tn, int cl)
  710. {
  711.     return new TreeNodeSelector(tn, cl);
  712. }
  713.  
  714. Command *TreeView::NodeSelected(VObject* vop, int cl)
  715. {
  716.     int partcode= cl >= 2 ? cPartTreeDoubleSelect: cPartTreeSelect;
  717.     Control(GetId(), partcode, (void*) vop);
  718.     return gNoChanges;
  719. }
  720.  
  721. Command *TreeView::DispatchEvents(Point lp, Token &t, Clipper *vf)
  722. {
  723.     if (dialogRoot && dialogRoot->ContainsPoint(lp))
  724.     return dialogRoot->Input(lp, t, vf);
  725.     return View::DispatchEvents(lp, t, vf);  
  726. }
  727.  
  728. void TreeView::SetSelection(VObject *vop)
  729. {
  730.     if (vop != selection) {
  731.     if (selection)
  732.         selection->ForceRedraw();
  733.     selection= vop;
  734.     if (selection) 
  735.         selection->ForceRedraw();
  736.     }
  737. }
  738.  
  739. VObject *TreeView::BuildTree(Object *op)
  740. {
  741.     VObject *g= NodeAsVObject(op);
  742.     SeqCollection *l= new OrdCollection;
  743.     l->Add(g);
  744.     Iterator *it= MakeChildrenIter(op);
  745.     if (it) {
  746.     Iter next(it); 
  747.     while (op= next()) {
  748.         VObject *newitem= BuildTree(op);
  749.         if (!newitem->IsKindOf(TreeNode)) {
  750.         SeqCollection *cp= new OrdCollection(1);
  751.         cp->Add(newitem);
  752.         newitem= MakeTreeNode(5, cp);
  753.         }
  754.         l->Add(newitem);
  755.     }
  756.     }
  757.     g= MakeTreeNode(4, l);
  758.     return g;
  759. }
  760.  
  761. TreeNode *TreeView::MakeTreeNode(int id, SeqCollection *items)
  762. {
  763.     return new TreeNode(id, items);
  764. }
  765.  
  766. VObject *TreeView::NodeAsVObject(Object *)
  767. {
  768.     AbstractMethod("AsVObject");
  769.     return 0;  
  770. }
  771.  
  772. Iterator *TreeView::MakeChildrenIter(Object *)
  773. {
  774.     AbstractMethod("GetSubPartsIter");
  775.     return 0;  
  776. }
  777.  
  778. void TreeView::InstallTree(Object *root)
  779. {
  780.     SetSelection(0);
  781.     SetTree((TreeNode*)BuildTree(root));    
  782. }
  783.